<template>
    <div class="joint-mind__wrapper">
         <div class="joint-mind__page" ref="jointExampleRef" id="paper"></div>
    </div>
</template>

<script setup>
import dagre from "dagre";
import graphlib from "@dagrejs/graphlib";
import { dia, shapes, layout, connectors, linkTools } from "jointjs";
import svgPanZoom from "svg-pan-zoom";
import "/node_modules/jointjs/dist/joint.css";
import { v4 as uuidV4 } from 'uuid';

defineOptions({
    name: 'JointBasic'
})

class Node extends dia.Element {
    // defaults() {
    //     return {
    //         ...super.defaults,
    //         type: "Node",
    //     };
    // }
    constructor(label = "节点名称") {
        super();
        this.id = uuidV4()
        this.label = label;
    }
}

const graph = ref(null);
const paper = ref(null);
const currCell = ref(null);
const jointExampleRef = ref(null);
// const nodes = reactive([
//     { id: 1, label: "node1" },
//     { id: 2, label: "node2" },
//     { id: 3, label: "node3" },
// ]);
// const links = reactive([
//     { from: 1, to: 2 },
//     { from: 1, to: 3 },
// ]);
const nodes = reactive([
    new Node("前端知识"),
    new Node("HTML"),
    new Node("JavaScript"),
    new Node("CSS"),
    new Node("Typescript"),
]);
const links = reactive([
    { from: nodes[0].id, to: nodes[1].id },
    { from: nodes[0].id, to: nodes[2].id },
    { from: nodes[0].id, to: nodes[3].id },
    { from: nodes[0].id, to: nodes[4].id }
]);
let nodeList = reactive([]);
let linkList = reactive([]);

// 初始化图形库
const initGraph = () => {
    nodeList = [];
    linkList = [];
    graph.value = new dia.Graph();
    paper.value = new dia.Paper({
        dagre: dagre, // 自动化布局
        graphlib: graphlib, // 处理图数据结构工具
        el: jointExampleRef.value,
        model: graph.value,
        width: "100%",
        height: "100%",
        background: {
            color: "#f5f5f5",
        },
        drawGrid: true,
        gridSize: 20,
    });
};

// 创建节点
const createNode = () => {
    nodes.forEach((ele) => {
        let node = new shapes.standard.Rectangle({
            id: ele.id,
            size: {
                width: 100,
                height: 50,
            },
            attrs: {
                body: {
                    fill: "#E74C3C",
                    stroke: "none",
                    ry: 10,
                    ry: 10,
                },
                label: {
                    text: ele.label,
                    fill: '#ECF0F1'
                }
            },
        });
        nodeList.push(node);
    });
    graph.value.addCell(nodeList);
};

// 创建连线规则
const createLink = () => {
    links.forEach((ele) => {
        let link = new shapes.standard.Link({
            smooth: true, // 连接器使用三次贝塞尔曲线插值路径点
            source: {
                id: ele.from,
            },
            target: {
                id: ele.to,
            },
            attrs: {
                line: {
                    stroke: "#aaa",
                    strokeWidth: 1,
                }
            },
        });
        /**
         * 曲线配置参数
         *  UP = 'up',
            DOWN = 'down',
            LEFT = 'left',
            RIGHT = 'right',
            AUTO = 'auto',
            CLOSEST_POINT = 'closest-point',
            OUTWARDS = 'outwards'
         * 
        */
        // link.connector('curve', {
        //     direction: connectors.curve.Directions.AUTO,
        //     targetDirection: connectors.curve.TangentDirections.AUTO
        // })
        linkList.push(link);
    });
    graph.value.addCell(linkList);
};

// 初始化布局方式，左右布局
const randomLayout = (redirect = 'LR') => {
    layout.DirectedGraph.layout(graph.value, {
        dagre: dagre, // 依赖于dagre布局工具
        graphlib: graphlib, // 依赖于graphlib有向多图库
        rankDir: redirect, // 布局方式
        rankSep: 200, // 代表等级之间间隔的像素数
        nodeSep: 30, // 表示同一等级中相邻节点之间间隔的像素数
        edgeSep: 100, // 表示同一等级中相邻边缘之间间隔的像素数 
    });
};

// 初始化缩放方法
const initSvgPanZoom = () => {
    if (nodes.length) {
        let svgZoom = svgPanZoom("#paper svg", {
            panEnabled: true,
            zoomEnabled: true,
            dblClickZoomEnabled: false,
            controlIconsEnabled: true, // 开启图标控制，点击图标缩放
            minZoom: 0.01,
            maxZoom: 100,
            fit: true,
            center: true,
            beforePan: (oldPan, newPan) => {
                if (currCell.value) {
                    return false;
                }
            },
        });
        svgZoom.setZoomScaleSensitivity(0.5);

        let { sx, sy } = paper.value.scale();
        if (sx > 1) {
            svgZoom.zoom(1 / sx);
        } else {
            svgZoom.zoom(0.9);
        }
    }
};

// 节点事件监听
const paperEvent = () => {
    paper.value.on("element:pointerdown", (cellView, evt, x, y) => {
        currCell.value = cellView;
    });
    paper.value.on("cell:pointerup blank:pointerup", (cellView, evt, x, y) => {
        currCell.value = null;
    });
};

onMounted(() => {
    initGraph();
    createNode();
    createLink();
    randomLayout();
    initSvgPanZoom();
    paperEvent();
    setTimeout(() => {
        // 背景图案放大缩小配置
        paper.value.scale(1, 1)
    }, 300);
});
</script>
<style lang="scss" src="./style.scss"></style>
